Spring Security 中的 RememberMe 登录,so easy!

您所在的位置:网站首页 remenberme 动画 Spring Security 中的 RememberMe 登录,so easy!

Spring Security 中的 RememberMe 登录,so easy!

2024-07-06 12:09:12| 来源: 网络整理| 查看: 265

松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。

1. RememberMe简介

RememberMe 这个功能非常常见,图 6-1 所示就是 QQ 邮箱登录时的“记住我”选项。

提到 RememberMe,一些初学者往往会有一些误解,认为 RememberMe 功能就是把用户名/密码用 Cookie 保存在浏览器中,下次登录时不用再次输入用户名/密码。这个理解显然是不对的。

我们这里所说的 RememberMe 是一种服务器端的行为。传统的登录方式基于 Session 会话,一旦用户关闭浏览器重新打开,就要再次登录,这样太过于烦琐。如果能有一种机制,让用户关闭并重新打开浏览器之后,还能继续保持认证状态,就会方便很多,RememberMe 就是为了解决这一需求而生的。

具体的实现思路就是通过 Cookie 来记录当前用户身份。当用户登录成功之后,会通过一定的算法,将用户信息、时间戳等进行加密,加密完成后,通过响应头带回前端存储在 Cookie 中,当浏览器关闭之后重新打开,如果再次访问该网站,会自动将 Cookie 中的信息发送给服务器,服务器对 Cookie 中的信息进行校验分析,进而确定出用户的身份,Cookie 中所保存的用户信息也是有时效的,例如三天、一周等。敏锐的读者可能已经发现这种方式是存在安全隐患的。所谓鱼与熊掌不可兼得,要想使用便利,就要牺牲一定的安全性,不过在本章中,我们将会介绍通过持久化令牌以及二次校验来降低使用 RememberMe 所带来的安全风险。

2. RememberMe基本用法

我们先来看一种最简单的用法。

首先创建一个 Spring Boot 工程,引入 spring-boot-starter-security 依赖。工程创建成功后,添加一个 HelloController 并创建一个测试接口,代码如下:

代码语言:javascript复制@RestController public class HelloController { @GetMapping("/hello") public String hello() { return "hello"; } }

然后创建 SecurityConfig 配置文件:

代码语言:javascript复制@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("javaboy") .password("123") .roles("admin"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .rememberMe() .key("javaboy") .and() .csrf().disable(); } }

这里我们主要是调用了 HttpSecurity 中的 rememberMe 方法并配置了一个 key,该方法最终会向过滤器链中添加 RememberMeAuthenticationFilter 过滤器。

配置完成后,启动项目,当我们访问 /hello 接口时,会自动重定向到登录页面,如图 6-2 所示。

可以看到,此时的默认登录页面多了一个 RememberMe 选项,勾选上 RememberMe,登录成功之后,我们就可以访问 /hello 接口了。访问完成后,关闭浏览器再重新打开,此时不需要登录就可以直接访问 /hello 接口;同时,如果关闭掉服务端重新打开,再去访问 /hello接口,发现此时也不需要登录了。

那么这一切是怎么实现的呢?打开浏览器控制台,我们来分析整个登录过程。

首先,当我们单击登录按钮时,多了一个请求参数 remember-me,如图6-3所示。

很明显,remember-me 参数就是用来告诉服务端是否开启 RememberMe 功能,如果开发者自定义登录页面,那么默认情况下,是否开启 RememberMe 的参数就是 remember-me。

当请求成功后,在响应头中多出了一个 Set-Cookie,如图 6-4 所示。

在响应头中给出了一个 remember-me 字符串。以后所有请求的请求头 Cookie 字段,都会自动携带上这个令牌,服务端利用该令牌可以校验用户身份是否合法。

大致的流程就是这样,但是大家发现这种方式安全隐患很大,一旦 remember-me 令牌泄漏,恶意用户就可以拿着这个令牌去随意访问系统资源。持久化令牌和二次校验可以在一定程度上降低该问题带来的风险。

3. 持久化令牌

使用持久化令牌实现 RememberMe 的体验和使用普通令牌的登录体验是一样的,不同的是服务端所做的事情变了。

持久化令牌在普通令牌的基础上,新增了 series 和 token 两个校验参数,当使用用户名/密码的方式登录时,series 才会自动更新;而一旦有了新的会话,token 就会重新生成。所以,如果令牌被人盗用,一旦对方基于 RememberMe 登录成功后,就会生成新的 token,你自己的登录令牌就会失效,这样就能及时发现账户泄漏并作出处理,比如清除自动登录令牌、通知用户账户泄漏等。

Spring Security中对于持久化令牌提供了两种实现:

JdbcTokenRepositoryImplInMemoryTokenRepositoryImpl

前者是基于 JdbcTemplate 来操作数据库,后者则是操作存储在内存中的数据。由于 InMemoryTokenRepositoryImpl 的使用场景很少,因此这里主要介绍基于 JdbcTokenRepositoryImpl 的配置。

首先创建一个 security06 数据库,然后我们需要一张表来记录令牌信息,创建表的 SQL 脚本在在 JdbcTokenRepositoryImpl 类中的 CREATE_TABLE_SQL 变量上已经定义好了,代码如下:

代码语言:javascript复制public static final String CREATE_TABLE_SQL = "create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, " + "token varchar(64) not null, last_used timestamp not null)";

我们直接将变量中定义的 SQL 脚本拷贝出来到数据库中执行,生成一张 persistent_logins 表用来记录令牌信息。persistent_logins 表一共就四个字段:username 表示登录用户名、series 表示生成的 series 字符串、token 表示生成的 token 字符串、last_used 则表示上次使用时间。

接下来,在项目中引入 JdbcTemplate 依赖和 MySQL 数据库驱动依赖:

代码语言:javascript复制 org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java

然后在 application.properties 中配置数据库连接信息:

代码语言:javascript复制spring.datasource.url=jdbc:mysql:///security06?useUnicode=true&characterEncod ing=UTF-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123

最后修改 SecurityConfig:

代码语言:javascript复制@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired DataSource dataSource; @Bean JdbcTokenRepositoryImpl jdbcTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); return jdbcTokenRepository; } @Bean PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("javaboy") .password("123") .roles("admin"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .rememberMe() .tokenRepository(jdbcTokenRepository()) .and() .csrf().disable(); } }

在配置中我们提供了一个 JdbcTokenRepositoryImpl 实例,并为其配置了数据源,最后在配置 RememberMe 时通过 tokenRepository 方法指定 JdbcTokenRepositoryImpl 实例。

配置完成后,启动项目并进行登录测试。登录成功后,我们发现数据库表中多了一条记录,如图6-5所示。

此时如果关闭浏览器重新打开,再去访问 /hello 接口,访问时并不需要登录,但是访问成功之后,数据库中的 token 字段会发生变化。同时,如果服务端重启之后,浏览器再去访问 /hello 接口,依然不需要登录,但是 token 字段也会更新,因为这两种情况中都有新会话的建立,所以 token 会更新,而 series 则不会更新。当然,如果用户注销登录,则数据库中和该用户相关的登录记录会自动清除。

可以看到,持久化令牌比前面的普通令牌安全系数提高了不少,但是依然存在风险。安全问题和用户的使用便捷性就像一个悖论,想要用户使用方便,不可避免地要牺牲一点安全性。对于开发者而言,要做的就是如何将系统存在的安全风险降到最低。

那么怎么办呢?二次校验可以帮助我们进一步降低风险。。。

本文节选自《深入浅出Spring Security》一书。

松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭